package com.grao.waterschool.human.manager.service.impl;

import cn.hutool.core.codec.Base64;
import cn.hutool.core.util.ObjectUtil;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.grao.waterschool.human.common.BusinessException;
import com.grao.waterschool.human.entiry.dto.UserLogin;
import com.grao.waterschool.human.manager.service.ICCAuthorizeService;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.*;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import javax.annotation.PostConstruct;
import javax.crypto.Cipher;
import java.nio.charset.StandardCharsets;
import java.security.KeyFactory;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.X509EncodedKeySpec;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@Slf4j
@Service
public class ICCAuthorizeServiceImpl implements ICCAuthorizeService {

    //获取publicKey
//    @Value("${URL.getPublicKeyURL}")
    static String getPublicKeyURL;

    @Value("${URL.getPublicKeyURL}")
    private String injectedPublicKeyURL;

    //登陆（获取Token）
//    @Value("${URL.getTokenURL}")
    static String getTokenURL = "http://10.0.25.224/evo-apigw/evo-oauth/1.0.0/oauth/extend/token";

    //secret 用于登陆
//    @Value("${URL.clientSecret}")
    static String clientSecret = "654fd914-75b5-4b19-bc3b-70477c574a48";

    //刷新Token
//    @Value("${URL.refreshTokenURL}")
    static String refreshTokenURL = "http://10.0.25.224/evo-apigw/evo-oauth/1.0.0/oauth/extend/refresh/token";

    @Autowired
    static StringRedisTemplate redisTemplate = new StringRedisTemplate();

    @Autowired
    private static RestTemplate restTemplate = new RestTemplate();

    static ObjectMapper objectMapper = new ObjectMapper();

    @PostConstruct
    public void init() {
        // 通过实例变量将值赋给静态变量
        getPublicKeyURL = injectedPublicKeyURL;
    }

    public ICCAuthorizeServiceImpl(RestTemplate restTemplate, StringRedisTemplate redisTemplate) {
        ICCAuthorizeServiceImpl.restTemplate = restTemplate;
        ICCAuthorizeServiceImpl.redisTemplate = redisTemplate;
    }

    /**
     * 登录ICC平台
     */
    @Override
    public Map<String, String> loginForICC() throws Exception {
        log.info("----------登录开始-----------");
        UserLogin userLogin = new UserLogin();
        userLogin.setUsername("xunke1");
        userLogin.setPwd("Admin!@#123");

        log.info("userLogin：{}", userLogin);
        //获取公钥
        String publicKey = getPublicKey();
        log.info("publicKey:{}", publicKey);

        String rsaPwd = RSAPwd(userLogin.getPwd(), publicKey);
        Map<String, String> token = getToken(userLogin.getUsername(), rsaPwd, publicKey);
        log.info("token:{}", token);
        return token;

    }

    /**
     * 大华要求用户密码需要publicKey+用户密码进行rsa加密并base64编码后再进行传输
     */
    private static String RSAPwd(String pwd, String PublicKey) throws Exception {
        byte[] decoded = Base64.decode(PublicKey);
        RSAPublicKey pubKey = (RSAPublicKey) KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(decoded));
        // RSA加密
        Cipher cipher = Cipher.getInstance("RSA");
        cipher.init(Cipher.ENCRYPT_MODE, pubKey);

        return Base64.encode(cipher.doFinal(pwd.getBytes(StandardCharsets.UTF_8)));
    }

    /**
     * 登陆获取token的流程
     */
    private static Map<String, String> getToken(String username, String rsaPwd, String publicKey) throws Exception {

        Map<String, String> requestBody = new HashMap<>();
        requestBody.put("grant_type", "password");
        requestBody.put("username", username);
        requestBody.put("password", rsaPwd);
        requestBody.put("client_id", "id");
        requestBody.put("client_secret", clientSecret);
        requestBody.put("public_key", publicKey);
        log.info("clientInfo:{}", clientSecret);
        log.info("requestBody:{}", requestBody);

        ObjectMapper mapper = new ObjectMapper();
        String jsonRequestBody = mapper.writeValueAsString(requestBody);

        HttpEntity<String> requestEntity = new HttpEntity<>(jsonRequestBody, getHttpHeaders());
        ResponseEntity<String> responseEntity = restTemplate.exchange(getTokenURL, HttpMethod.POST, requestEntity, String.class);

        ObjectMapper objectMapper = new ObjectMapper();
        JsonNode rootNode = objectMapper.readTree(responseEntity.getBody());

        if (rootNode.has("success") && rootNode.get("success").asBoolean()) {
            JsonNode dataNode = rootNode.get("data");
            if (dataNode != null) {
                Map<String, String> tokenInfo = new HashMap<>();
                if (dataNode.has("userId")) {
                    tokenInfo.put("userId", dataNode.get("userId").asText());
                    log.info("userID:{}", tokenInfo.get("userId"));
                }
                if (dataNode.has("access_token")) {
                    tokenInfo.put("accessToken", dataNode.get("access_token").asText());
                    log.info("access_token:{}", tokenInfo.get("accessToken"));
                }
                if (dataNode.has("refresh_token")) {
                    tokenInfo.put("refreshToken", dataNode.get("refresh_token").asText());
                    log.info("refreshToken:{}", tokenInfo.get("refreshToken"));
                }

                // 将用户的俩token存入redis，accessToken有效期7200秒，refreshToken有效期6天
                redisTemplate.opsForValue().set(tokenInfo.get("userId") + "accessToken", tokenInfo.get("accessToken"), 120, TimeUnit.MINUTES);
                redisTemplate.opsForValue().set(tokenInfo.get("userId") + "refreshToken", tokenInfo.get("refreshToken"), 120, TimeUnit.MINUTES);

                return tokenInfo;
            } else {
                throw new Exception("Data node is null.");
            }
        } else {
            throw new Exception("请求失败，代码显示：" + (rootNode.has("code") ? rootNode.get("code").asText() : "null") + ", errMsg: " + (rootNode.has("errMsg") ? rootNode.get("errMsg").asText() : "null"));
        }
    }

    /**
     * 刷新Token（accessToken有效期两小时，RefreshToken有效期6天，所以不用管RefreshToken的过期时间）
     */
    public static String refreshToken(Integer userId) throws Exception {
        String userKey = userId + "refreshToken";
        log.info("查询名称为：{}", userKey);

        String refreshToken = redisTemplate.opsForValue().get(userKey);
        log.info("refreshToken是:{}", refreshToken);

        if (refreshToken == null) {
//            throw new BusinessException("抱歉，登录已过期，请重新登录。");
            log.info("----------登录开始-----------");
            UserLogin userLogin = new UserLogin();
            userLogin.setUsername("xunke1");
            userLogin.setPwd("Admin!@#123");

            log.info("userLogin：{}", userLogin);
            //获取公钥
            String publicKey = getPublicKey();
            log.info("publicKey:{}", publicKey);

            String rsaPwd = RSAPwd(userLogin.getPwd(), publicKey);
            Map<String, String> token = getToken(userLogin.getUsername(), rsaPwd, publicKey);
            refreshToken = token.get("refreshToken");
            if (ObjectUtil.isEmpty(refreshToken)) throw new BusinessException("抱歉，登录已过期，请重新登录。");
            log.info("token:{}", token);
        }

        Map<String, String> requestBody = new HashMap<>();
        requestBody.put("grant_type", "refresh_token");
        requestBody.put("refresh_token", refreshToken);
        requestBody.put("client_id", "id");
        requestBody.put("client_secret", clientSecret);
        log.info("requestBody:{}", requestBody);

        ObjectMapper mapper = new ObjectMapper();
        String jsonRequestBody = mapper.writeValueAsString(requestBody);

        HttpEntity<String> requestEntity = new HttpEntity<>(jsonRequestBody, getHttpHeaders());
        ResponseEntity<String> responseEntity = restTemplate.exchange(refreshTokenURL, HttpMethod.POST, requestEntity, String.class);

        ObjectMapper objectMapper = new ObjectMapper();
        JsonNode rootNode = objectMapper.readTree(responseEntity.getBody());
        log.info("responseEntity:{}", responseEntity);

        if (rootNode.path("success").asBoolean()) {
            Map<String, String> tokenInfo = new HashMap<>();
            tokenInfo.put("userId", rootNode.path("data").path("userId").asText());
            String newtoken = rootNode.path("data").path("access_token").asText();
            tokenInfo.put("accessToken", newtoken);
            tokenInfo.put("refreshToken", rootNode.path("data").path("refresh_token").asText());

            //将用户的俩token存入redis，accessToken有效期7200秒，refreshToken有效期1天
            redisTemplate.opsForValue().set(tokenInfo.get("userId") + "accessToken", tokenInfo.get("accessToken"), 120, TimeUnit.MINUTES);
            redisTemplate.opsForValue().set(tokenInfo.get("userId") + "refreshToken", tokenInfo.get("refreshToken"), 1, TimeUnit.DAYS);

            return newtoken;
        } else {
            throw new Exception("请求失败，代码显示：" + rootNode.path("code").asText() + ", errMsg: " + rootNode.path("errMsg").asText());
        }
    }

    /**
     * 获取公钥
     */
    private static String getPublicKey() {
        HttpEntity<String> requestEntity = new HttpEntity<>(getHttpHeaders());
        if (restTemplate == null) {
            throw new IllegalStateException("Required objects are null");
        }
        ResponseEntity<String> response = restTemplate.exchange(getPublicKeyURL, HttpMethod.GET, requestEntity, String.class);
        log.info("response:{}", response);

        if (response.getStatusCode() != HttpStatus.OK) {
            throw new BusinessException("获取公钥失败");
        }

        try {
            JsonNode rootNode = objectMapper.readTree(response.getBody());

            if (rootNode.has("success") && rootNode.path("success").asBoolean()) {
                JsonNode dataNode = rootNode.path("data");
                if (dataNode.has("publicKey")) {
                    return dataNode.path("publicKey").asText();
                } else {
                    throw new BusinessException("公钥数据缺失");
                }
            } else {
                String errMsg = rootNode.has("errMsg") ? rootNode.path("errMsg").asText() : "未知错误";
                throw new BusinessException("获取公钥失败：" + errMsg);
            }
        } catch (JsonProcessingException e) {
            throw new BusinessException("解析响应失败：" + e.getMessage());
        }
    }

    /**
     * 公用的获取请求头
     */
    private static HttpHeaders getHttpHeaders() {
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        return headers;
    }
}
